-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Fix negative delta scroll #19573
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix negative delta scroll #19573
Conversation
This fixes the negative delta scroll by correctly allowing for 16-bit to 32-bit sign extension by implicit type promotion.
| const winrt::Windows::Foundation::Point real{ relative.x / scale, relative.y / scale }; | ||
|
|
||
| winrt::Microsoft::Terminal::Core::Point wheelDelta{ 0, static_cast<int32_t>(HIWORD(wparam)) }; | ||
| winrt::Microsoft::Terminal::Core::Point wheelDelta{ 0, static_cast<int16_t>(HIWORD(wparam)) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh... yeah that makes sense.
We could further improve this by using std::bit_cast<int16_t> here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review and the feedback! As suggested I changed it to a std::bit_cast!
I was wondering if the bit header should be also included. I grepped through the code to see for previous std::bit_cast usages, but I couldn't find any direct references to that header. I also grepped for that specific header, but there wasn't any match. Maybe the MSVC compiler handles it as a built-in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It probably gets pulled in implicitly through another header.
lhecker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again!
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Ah, so this regressed with #19248? I'll mark it up for servicing to all the versions that got that fix. Thanks so much (seriously) for tracking this down. |
In my history of software engineering, it is always the shortest fixes which require the longest explanations. I'm 100% here for it. :D |
|
I'm really glad I could be of help! Yes, that's the PR where the issue started! All in all I had a lot of fun trying to figure out what was happening under the hood (I like reverse engineering), plus having the PDB symbols available alongside the source code helped a lot. |
Summary of the Pull Request
This fixes the negative delta scroll by correctly allowing for 16-bit to 32-bit sign extension by implicit type promotion.
References and Relevant Issues
#19484 #19391 (I might be wrong about the second one, but it looks similar since the thumb of the scrollbar is stuck on the top)
Detailed Description of the Pull Request / Additional comments
Hello!
After updating to the latest Windows Terminal Preview version, I've been experiencing an issue with the touchpad, when scrolling.
To be more precise, it started since v1.24.2682.0.
The issue happens only when scrolling down (that is to say when the thumb of the scrollbar should move down).
And, basically, it scrolls in reverse all the way up even with a minimum amount of scroll.
Scrolling up, instead, works as expected.
Given the premise, I decided to give it a chance and see if I could fix it.
I don't have the needed VS environment to compile the code, so I used a debugger (x64dbg) to adventure myself in this "quest".
After literally 3 hours of misplaced breakpoints I started to notice a pattern.
For starters the interesting code path is the
AppHost::_WindowMouseWheeledmethod.I'll add a visual screenshot diff between the Preview and Stable version and I'll try my best to explain in words what I discovered.
By the way, I made sure to scroll the same amount in both versions so they are easily comparable.
Screenshots
Windows Terminal Preview
Windows Terminal Stable
What's really interesting is the R8 register. It contains the delta scroll and it corresponds to the second parameter of the
_WindowMouseWheeledmethod.int32_tstored as 32-bit in the second half of the register.winrt::Microsoft::Terminal::Core::Pointwhich seems to be nicely packed into the R8 register as Y + X (32-bit + 32-bit, which is cool!).However, despite this, there's another important difference between the two versions: it's the sign part of the delta scroll.
In the Stable version it's correctly stored as a 32-bit signed integer, but in the Preview version it's stored as a 16-bit signed integer which is wrong, because it's going to be read as a 32-bit signed integer.
Basically:
0xFFFFFF58->-1680x0000FF58->65368In the Preview version it becomes a huge positive number and that's why the thumb of the scrollbar goes all the way up.
Just to be sure I tried to manually patch the R8 register to its correct value
FFFFFF5800000000and it works as expected.When looking at the source code and, specifically, the b53d7df commit, there's this code change to the
IslandWindow.cppfile which seems to be the source of the issue:I literally went by exclusion since that's where the param is set and nothing else happens in-between (there's also a
std::swap, but it's not really relevant).So I had an idea and I tried to write a really small C++ program to test the integer conversion. And, indeed, I could replicate the same issue.
I also mocked the
HIWORDmacro just to be sure I had a similar approach to that of the original code.Here's the snippet:
Code Snippet
I compiled the snippet with
gcc --pedantic --std=c++17 -Wall -O0 -o test main.cpp, but I suppose the same output should apply for Visual Studio.That being said, I think there are two potential approaches to fix the issue:
The first fix is much more verbose and it was the one I wanted to commit, just to be safe (since I can't really test the whole Terminal compilation).
The second one, which I ended up choosing, relies on the implicit type promotion, but it also should work (or at least I hope so!).
As a bonus, since I was already in the debugger rabbit hole, I wanted to see where the proper sign conversion happened in the Stable version and here it is:
Screenshot
Windows Terminal Stable
There's an intermediate function call where the
movsx eax, word ptr ds:[r8]instruction is used.Which is literally
Move with Sign-Extension. It takes the delta scroll from the stack to "fix" it intoeax.One last fun thing: if I enable the precision touchpad, in Windows settings, the issue doesn't happen at all.
That's because a completely different code path is executed, namely
TermControl::_MouseWheelHandler.I apologize for the long message considering the fix is really tiny!
Validation Steps Performed
Tested with a debugger and wrote a code snippet
PR Checklist